home *** CD-ROM | disk | FTP | other *** search
- /* Font.C
- *
- * Anything having to do with changing the style, family, or size of the
- * fonts is handled through this Font class.
- *
- * Copyright 1992 Jonathan Monsarrat. Permission given to freely distribute,
- * edit and use as long as this copyright statement remains intact.
- *
- */
-
- #include "Global.h"
- #include "Font.h"
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
-
- FontUsed *Font::_fonts_used[MAXFONTS];
- int Font::_num_fonts_used;
-
- // Build a list of fonts actually used, along with the characters
- // used for each font.
- FontUsed::FontUsed(char *style, char *petname, int font)
- {
- strcpy(_style, style);
- strcpy(_petname, petname);
- _font = font;
- for(int x=0; x<256; x++)
- _charused[x] = (x >= '0' && x <= '9') ? 1 : 0;
- }
-
- void FontUsed::used(char *textstr)
- {
- for(int x=0; textstr[x]; x++)
- _charused[textstr[x]] = 1;
- }
-
- int FontUsed::font()
- {
- return _font;
- }
-
- void FontUsed::dump(ofstream &outfile)
- {
- outfile << "{" << _style << endl;
-
- int num=0;
- for(int x=0; x < 256; x++)
- if(_charused[x]) {
- if(num++ > 25) {
- outfile << endl << endl;
- num=0;
- }
- switch(x) {
- case '^': // Can't handle these. Sorry!
- case '{':
- case '}':
- break;
- case '&':
- case '#':
- case '_':
- case '%':
- case '$':
- outfile << '\\';
- default:
- outfile << (char) x << " ";
- break;
- }
- }
-
- outfile << "`` '' ." << endl;
- outfile << "}" << endl;
- }
-
- int FontUsed::match(char *textstr)
- {
- return !strcmp(textstr,_petname);
- }
-
- char *FontUsed::petname()
- {
- return _petname;
- }
-
- Font::Font()
- {
- _basesize = 10;
- _fontsize = 10;
- strcpy(_fontstyle,"rm");
- strcpy(_fontsizecmd,"\\normalsize");
- _fonts_used[0] = new FontUsed("\\normalsize\\rm", "/cm10rm", 1);
- _num_fonts_used = 1;
- Global::files->outfile << endl;
- _currentused = 0;
- _pending = 1;
- _pending_whitespace = 1;
- }
-
- Font::Font(Font *base)
- {
- _basesize = base->_basesize;
- _fontsize = base->_fontsize;
- strcpy(_fontstyle, base->_fontstyle);
- strcpy(_fontsizecmd, base->_fontsizecmd);
- _currentused = base->_currentused;
- _pending = base->_pending;
- _pending_whitespace = base->_pending_whitespace;
- }
-
- Font::~Font()
- {
- for(int x=0; x < _num_fonts_used; x++)
- delete _fonts_used[x];
- }
-
- Param *Font::copy()
- {
- return new Font(this);
- }
-
-
- void Font::newsize(float val)
- {
- if(_fontsize != val) {
- _fontsize = (int) val;
-
- /* We are updating the size of the font, so we had better update
- * also the amount of space to skip between lines. This is done
- * by doing a set statement on \baselinestretch.
- */
- if(!Global::files->plain_text_output) {
- Stack::set(Environment::PLength, 0,
- Stack::get(Environment::PLength, Length::Parameter,
- "\\baselinestretch"), "\\baselinestretch");
- }
- _pending = 1; // Print the postscript command for this.
- _pending_whitespace = Global::files->whitespace_next();
- }
- }
-
- void Font::set_fontstyle(char *style)
- {
- if(strcmp(_fontstyle,style)!=0) {
- strcpy(_fontstyle,style);
- _pending = 1; // Print the postscript command for this.
- _pending_whitespace = Global::files->whitespace_next();
- }
- }
-
- int Font::set(int subtype, float value, char *textstr)
- {
- /* The Font Family is hard-coded to "cm" for Computer Modern */
- switch(subtype) {
- /* Base sizes */
- case Base10pt: // Do nothing; this is the default.
- break;
- case Base11pt:
- delete _fonts_used[0];
- _fonts_used[0] = new FontUsed("\\normalsize\\rm", "/cm11rm", 1);
- Global::files->outfile << endl;
- Global::files->outfile << "/basefont /cm11rm def" << endl;
- _basesize = 11;
- _fontsize = 11;
- _pending = 1;
- _pending_whitespace = Global::files->whitespace_next();
- break;
- case Base12pt:
- delete _fonts_used[0];
- _fonts_used[0] = new FontUsed("\\normalsize\\rm", "/cm12rm", 1);
- Global::files->outfile << endl;
- Global::files->outfile << "/basefont /cm12rm def" << endl;
- _basesize = 12;
- _fontsize = 12;
- _pending = 1;
- _pending_whitespace = Global::files->whitespace_next();
- break;
-
- /* _Font styles */
- case Italic:
- if(strcmp(_fontstyle,"it")==0)
- strcpy(_fontstyle,"rm"); // Double Italic is Roman!
- else
- strcpy(_fontstyle,"it");
- _pending = 1; // Print the postscript command for this.
- _pending_whitespace = Global::files->whitespace_next();
- break;
- case Bold:
- set_fontstyle("bf");
- break;
- case Roman:
- set_fontstyle("rm");
- break;
- case SansSerif:
- set_fontstyle("sf");
- break;
- case Slant:
- set_fontstyle("sl");
- break;
- case SmallCaps:
- set_fontstyle("sc");
- break;
- case Typewriter:
- set_fontstyle("tt");
- break;
-
- /* Sizes relative to the base size */
- case Tiny:
- strcpy(_fontsizecmd,"\\tiny");
- switch(_basesize) {
- case 10:
- default:
- newsize(4);
- break;
- case 11:
- case 12:
- newsize(6);
- break;
- }
- break;
- case Scriptsize:
- strcpy(_fontsizecmd,"\\scriptsize");
- switch(_basesize) {
- case 10:
- default:
- newsize(6);
- break;
- case 11:
- case 12:
- newsize(7);
- break;
- }
- break;
- case Footnotesize:
- strcpy(_fontsizecmd,"\\footnotesize");
- switch(_basesize) {
- case 10:
- default:
- newsize(7);
- break;
- case 11:
- newsize(8);
- break;
- case 12:
- newsize(10);
- break;
- }
- break;
- case Small:
- strcpy(_fontsizecmd,"\\small");
- switch(_basesize) {
- case 10:
- default:
- newsize(8);
- break;
- case 11:
- newsize(10);
- break;
- case 12:
- newsize(11);
- break;
- }
- break;
- case Normalsize:
- strcpy(_fontsizecmd,"\\normalsize");
- newsize(_basesize);
- break;
- case large:
- strcpy(_fontsizecmd,"\\large");
- switch(_basesize) {
- case 10:
- default:
- newsize(11);
- break;
- case 11:
- newsize(12);
- break;
- case 12:
- newsize(13);
- break;
- }
- break;
- case Large:
- strcpy(_fontsizecmd,"\\Large");
- switch(_basesize) {
- case 10:
- case 11:
- default:
- newsize(13);
- break;
- case 12:
- newsize(15);
- break;
- }
- break;
- case LARGE:
- strcpy(_fontsizecmd,"\\LARGE");
- switch(_basesize) {
- case 10:
- case 11:
- default:
- newsize(15);
- break;
- case 12:
- newsize(18);
- break;
- }
- break;
- case huge:
- strcpy(_fontsizecmd,"\\huge");
- switch(_basesize) {
- case 10:
- case 11:
- default:
- newsize(18);
- break;
- case 12:
- newsize(22);
- break;
- }
- break;
- case Huge:
- strcpy(_fontsizecmd,"\\Huge");
- newsize(22);
- break;
- case Currentused:
- _currentused = do_command(textstr, textstr,
- Global::files->whitespace_next(), 0);
- break;
- case Pending:
- if(_pending) {
- postscript_set(0);
- _pending = 0;
- }
- break;
- case Size:
- set_fontstyle("");
- newsize(value);
- break;
- /* These font styles aren't handled right now */
- case Used:
- _fonts_used[_currentused]->used(textstr);
- break;
- case FunnyPrint:
- Global::files->outfile << endl << "[ 0";
- if(Global::files->whitespace_next())
- Global::files->outfile << " false";
- else
- Global::files->outfile << " true";
- Global::files->outfile << " ] NewFont " << textstr << " NW " << endl;
- _pending = 1; // Print the postscript command for this.
- _pending_whitespace = Global::files->whitespace_next();
- // postscript_set(0);
- break;
- default:
- break;
- }
- return TRUE;
- }
-
- float Font::get(int subtype, char *comparestr)
- {
- switch(subtype) {
- case Base:
- return(_basesize);
- case Currentused:
- return(_currentused);
- case Pending:
- return(_pending);
- case Style:
- return(!strcmp(comparestr,_fontstyle));
- case ShutDown:
- if(!Global::files->plain_text_output)
- shutdown();
- break;
- case Size:
- default:
- break;
- }
- return(_fontsize);
- }
-
- void Font::revert(Param *from)
- {
- int size = (int)from->get(Size,"");
-
- if(size != _fontsize || !from->get(Style,_fontstyle)
- || from->get(Pending,"") || _currentused != from->get(Currentused,""))
- _pending = 1; // Print the postscript command for this.
- _pending_whitespace = Global::files->whitespace_next();
- }
-
- void Font::use_command(char *style, char *petname, int font)
- {
- _fonts_used[_num_fonts_used++] = new FontUsed(style,petname, font);
- }
-
- int Font::do_command(char *style, char *petname, int whitespace, int font)
- {
- for(int used=0; used < _num_fonts_used; used++)
- if(_fonts_used[used]->match(petname))
- break;
- if(_num_fonts_used >= MAXFONTS)
- Global::files->fatal_error("Too many fonts");
- if(used >= _num_fonts_used)
- use_command(style, petname, font);
-
- Global::files->outfile << endl << "[ " << used+1;
-
- if(whitespace)
- Global::files->outfile << " false";
- else
- Global::files->outfile << " true";
-
- Global::files->outfile << " ] NewFont % " << petname << endl;
- return(used);
- }
-
- void Font::postscript_set(int)
- {
- /* The Font Family is hard-coded to "cm" for Computer Modern */
- char petname[MAXSTRING];
-
- sprintf(petname,"/cm%d%s",_fontsize,_fontstyle);
- char style[MAXSTRING];
- sprintf(style,"%s\\%s",_fontsizecmd,_fontstyle);
- _currentused = do_command(style, petname, _pending_whitespace, 1);
- }
-
- // This is an important routine which builds a dummy latex files
- // Just to trick LaTeX into giving us the proper fonts.
- void Font::shutdown()
- {
- cerr << "Making dummy file for snarfing LaTeX fonts..." << endl;
- ofstream dummy("lametex.tex");
- if(_basesize == 10)
- dummy << "\\documentstyle{report}" << endl;
- else
- dummy << "\\documentstyle[" << _basesize << "pt]{report}" << endl;
- dummy << "\\pagestyle{empty}" << endl;
- dummy << "\\begin{document}" << endl;
- for(int x=0; x < _num_fonts_used; x++)
- _fonts_used[x]->dump(dummy);
- dummy << "\\end{document}" << endl;
- dummy.close();
- cerr << "Snarfing LaTeX fonts..." << endl;
- system( LATEX );
- system( DVIPS );
-
- ifstream latex_postscript("lametex.ps");
- if(!latex_postscript) { // Open file failed?
- cerr << "Unable to open postscript temp file lametex.ps for reading"
- << endl;
- exit (-1);
- }
-
- ofstream lametex_postscript("lametex.PS");
- if(!lametex_postscript) { // Open file failed?
- cerr << "Unable to open postscript temp file lametex.PS for writing"
- << endl;
- exit (-1);
- }
-
- char line[MAXSTRING];
- while(!latex_postscript.eof()) {
- latex_postscript.getline(line, MAXSTRING, '\n');
- if(strstr(line,"TeXDict begin")==line)
- break;
- }
-
- lametex_postscript << line << endl;
- while(!latex_postscript.eof()) {
- latex_postscript.getline(line, MAXSTRING, '\n');
- lametex_postscript << line << endl;
- if(strstr(line,"%%EndSetup"))
- break;
- }
-
- int y;
- for(x=_num_fonts_used-1, y=0; x >= 0 ; x--)
- if(_fonts_used[x]->font())
- lametex_postscript << _fonts_used[x]->petname()
- << "{ pop F" << (char) ('a' + y++)
- << " } bind def" << endl;
-
- lametex_postscript << "/fontnames [" << endl;
- lametex_postscript << "/TIMESROMAN" << endl;
-
- for(x=0; x < _num_fonts_used; x++)
- lametex_postscript << _fonts_used[x]->petname() << endl;
- lametex_postscript << "] def" << endl;
-
- latex_postscript.close();
- lametex_postscript.close();
- system("rm lametex.tex lametex.dvi lametex.ps");
- cerr << " ** SNARF! **" << endl;
- }
-